package jp.co.cos.ittrick.channel.service;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import jp.co.cos.ittrick.channel.Constants;
import jp.co.cos.ittrick.channel.meta.FileBytesModelMeta;
import jp.co.cos.ittrick.channel.meta.FileModelMeta;
import jp.co.cos.ittrick.channel.model.FileBytesModel;
import jp.co.cos.ittrick.channel.model.FileModel;

import org.slim3.controller.upload.FileItem;
import org.slim3.datastore.Datastore;
import org.slim3.util.ByteUtil;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;

public class FileService {

    private static final int FRAGMENT_SIZE = 900000;

    private FileModelMeta meta = FileModelMeta.get();

    private FileBytesModelMeta f = FileBytesModelMeta.get();

    /**
     * 全データのリストの取得
     * @return
     */
    public List<FileModel> getDataList() {
        return Datastore.query(meta).asList();
    }


    /**
     * Application のデータ一覧を取得
     * @return List<FileModel>
     */
    public List<FileModel> getDataListOfApplication() {
        return Datastore.query(meta).filter(meta.filePath.startsWith(Constants.FILES_START_WITH_KEY_APPLICATION)).asList();
    }


    /**
     * Channel のデータ一覧を取得
     * @return List<FileModel>
     */
    public List<FileModel> getDataListOfChannel(String channelKey) {
        String startWidthTxt = Constants.FILES_START_WITH_KEY_CHANNEL + "_" + channelKey;

        return Datastore.query(meta).filter(meta.filePath.startsWith(startWidthTxt)).asList();
    }


    /**
     * Page のデータ一覧を取得
     * @return List<FileModel>
     */
    public List<FileModel> getDataListOfPage(int pageKey) {

        String startWidthTxt = Constants.FILES_START_WITH_KEY_PAGE + "_" + pageKey;

        return Datastore.query(meta).filter(meta.filePath.startsWith(startWidthTxt)).asList();
    }

    /**
     * Article のデータ一覧を取得
     * @return List<FileModel>
     */
    public List<FileModel> getDataListOfArticle(int articleKey) {

        String startWidthTxt = Constants.FILES_START_WITH_KEY_ARTICLE + "_" + articleKey;

        return Datastore.query(meta).filter(meta.filePath.startsWith(startWidthTxt)).asList();
    }

    /**
     * Application のデータ アップロード
     * @param formFile
     * @return FileModel
     */
    public FileModel uploadForApplication(FileItem formFile) {
        return this.upload(formFile, Constants.FILES_START_WITH_KEY_APPLICATION);
    }

    /**
     * Channel のデータ アップロード
     * @param formFile
     * @return FileModel
     */
    public FileModel uploadForChannel(FileItem formFile, String channelKey) {

        String startWidthTxt = Constants.FILES_START_WITH_KEY_CHANNEL + "_" + channelKey;

        return this.upload(formFile, startWidthTxt);
    }

    /**
     * Page のデータ アップロード
     * @param formFile
     * @return FileModel
     */
    public FileModel uploadForPage(FileItem formFile, int pageKey) {

        String startWidthTxt = Constants.FILES_START_WITH_KEY_PAGE + "_" + pageKey;

        return this.upload(formFile, startWidthTxt);
    }


    /**
     * Article のデータ アップロード
     * @param formFile
     * @return FileModel
     */
    public FileModel uploadForArticle(FileItem formFile, int articleKey) {

        String startWidthTxt = Constants.FILES_START_WITH_KEY_ARTICLE + "_" + articleKey;

        return this.upload(formFile, startWidthTxt);
    }




    private FileModel upload(FileItem formFile, String filePath) {
        if (formFile == null) {
            return null;
        }
        List<Object> models = new ArrayList<Object>();
        FileModel data = new FileModel();
        models.add(data);
// --------------------キー方式の変更--------------------------------------
        Key key = Datastore.allocateId(meta);
        data.setKey(key);

        String filePathTex = filePath + "_" + key.getId();
        data.setFilePath(filePathTex);
//        Key fileKey = Datastore.createKey(meta, filePath);
//        data.setKey(fileKey);
// ------------------------------------------------------------------------
        data.setFileName(formFile.getShortFileName());
        data.setLength(formFile.getData().length);
        byte[] bytes = formFile.getData();
        byte[][] bytesArray = ByteUtil.split(bytes, FRAGMENT_SIZE);
        Iterator<Key> keys =
            Datastore
                .allocateIds(data.getKey(), f, bytesArray.length)
                .iterator();
        for (int i = 0; i < bytesArray.length; i++) {
            byte[] fragmentData = bytesArray[i];
            FileBytesModel fragment = new FileBytesModel();
            models.add(fragment);
            fragment.setKey(keys.next());
            fragment.setBytes(fragmentData);
            fragment.setIndex(i);
            fragment.getImageModelRef().setModel(data);
        }
        Transaction tx = Datastore.beginTransaction();
        for (Object model : models) {
            Datastore.put(tx, model);
        }
        tx.commit();
        return data;
    }

    public FileModel getData(Key key, Long version) {
        return Datastore.get(meta, key, version);
    }

    public FileModel getData(int pkKey) {
    	Key fileKey = Datastore.createKey(meta, pkKey);
    	return Datastore.getOrNull(meta, fileKey);
    }

    public byte[] getBytes(FileModel uploadedData) {
        if (uploadedData == null) {
            throw new NullPointerException(
                "The uploadedData parameter must not be null.");
        }
        List<FileBytesModel> fragmentList =
            uploadedData.getImageByteModelListRef().getModelList();
        byte[][] bytesArray = new byte[fragmentList.size()][0];
        for (int i = 0; i < fragmentList.size(); i++) {
            bytesArray[i] = fragmentList.get(i).getBytes();
        }
        return ByteUtil.join(bytesArray);
    }

    public void delete(Key key) {
        Transaction tx = Datastore.beginTransaction();
        List<Key> keys = new ArrayList<Key>();
        keys.add(key);
        keys.addAll(Datastore.query(f, key).asKeyList());
        Datastore.delete(tx, keys);
        tx.commit();
    }

    public void delete(int pkKey) {
    	Key fileKey = Datastore.createKey(meta, pkKey);
    	this.delete(fileKey);
    }
}


